//
//  STDRenderManager.hpp
//  STDRenderSDK
//
//  Created by 陈学明 on 2023/3/13.
//  Copyright © 2023 陈学明. All rights reserved.
//

#ifndef RenderManager_hpp
#define RenderManager_hpp

#include "STDSGLContext.hpp"
#include <Basic/Shader/STDSEffectManager.hpp>
#include <Effects/STDSBaseEffect.hpp>
#include <Basic/Attrib/STDSAttribRect.hpp>
#include <Layer/STDLayerHeader.h>
#include <Effects/STDSBlendEffect.hpp>
#include <Effects/STDSDefaultEffect.hpp>
#include <thread>
using namespace std;

class STDRenderManager {
public:
    STDRenderManager() {
        mContext = make_shared<STDSGLContext>();
        mBlendEffect = make_shared<STDSBlendEffect>();
        mBlendEffect->setContext(mContext);
        
        mDefaultEffect = make_shared<STDSDefaultEffect>();
        mDefaultEffect->setContext(mContext);
    }
    ~STDRenderManager() {
//        printf("dealloc--STDRenderManager\n");
    }
    static void release(STDRenderManager *m) {
        if (m != nullptr) {
            delete m;
        }
    }

public:
    void setSizeSRC(int width, int height) {
        std::lock_guard<std::mutex> lock(mMutex);
        mContext->setSizeSRC(glm::vec2(width, height));
        mContext->setSizeCVS(glm::vec2(width, height));
    }
    
    void setComposeDuration(float duration) {
        std::lock_guard<std::mutex> lock(mMutex);
        mDuration = duration;
        mContext->setDuration(duration);
    }
    
    void setRegisterProvider(shared_ptr<STDSProvider> provider) {
        std::lock_guard<std::mutex> lock(mMutex);
        mContext->setRegisterProvider(provider);
    }
    
public:
    void addLayer(int layerID, int layerType);
    
    void moveLayerToCompose(int layerID, int composeID);
    
    void removeLayer(int layerID);
    
    void setSolidLayerColor(int layerId, float r, float g, float b);
    
    
    void moveLayerToFront(int composeID, int layerID, int targetLayerID);
    
    void moveLayerToBack(int composeID, int layerID, int targetLayerID);
    
    void moveLayerToTop(int composeID, int layerID);
    
    void moveLayerToBottom(int composeID, int layerID);
    
    
    void visibleLayer(int layerID, int isVisible);
    
    void setLayerLife(int layerID, float start, float duration);
    
    void setLayerAlpha(int layerID, float alpha);
    
    void setLayerBlend(int layerID, int blend);
    
    void setLayerSize(int layerID, float w, float h);
    
    void setLayerCenter(int layerID, float x, float y);
    
    void setLayerScale(int layerID, float x, float y);
    
    void setLayerRotate(int layerID, float angle);
    
    void setLayerAutoSize(int layerID, bool autoW, bool autoH);
    
    void transformationTranslation(int layerID, float dx, float dy);
    
    void transformationScale(int layerID, float dx, float dy);
    
    void transformationRotation(int layerID, float dAngle);
    
    shared_ptr<STDBaseLayer> getLayer(int layerID);
    
    shared_ptr<STDBaseLayer> popLayer(int layerID);
public:
    void addEffect(int layerID, int effect);
    
    void changeEffectFloatValue(int layerID, int effect, const char *paramName, float *floatValue, int n);
    
    void changeEffectIntValue(int layerID, int effect, const char *paramName, int *intValue, int n);

    void changeEffectStringValue(int layerID, int effect, const char *paramName, const char *stringValue);
    
    void changeEffectBitmap(int layerID, int effectType, const char *paramName, const char *data, int width, int height);
    
    void changeEffectTex(int layerID, int effectType, const char *paramName, unsigned int texId, int width, int height);
    
    void removeEffect(int layerID, int effect);
    
    void visibleEffect(int layerID, int effectType, int isVisible);
    
    bool checkEffectStatus(int layerID, int effectType, const char *label);
    
public:
    void addHotEffect(int layerID, const char *effectName, const char *effectRoot);
    
    void removeHotEffect(int layerID, const char *effectName);
    
    void changeHotEffectFloatValue(int layerID, const char *effectName, const char *paramName, float *floatValue, int n);
    
    void changeHotEffectIntValue(int layerID, const char *effectName, const char *paramName, int *intValue, int n);
    
    void changeHotEffectStringValue(int layerID, const char *effectName, const char *paramName, const char *stringValue);
    
    void visibleHotEffect(int layerID, const char *effectName, int isVisible);
    
public:
    void addHotFilter(int layerID, const char *filter, const char *effectRoot);
    
    void removeHotFilter(int layerID, const char *filter);
    
    void changeHotFilterFloatValue(int layerID, const char *filter, const char *effectName, const char *paramName, float *floatValue, int n);
    
    void changeHotFilterIntValue(int layerID, const char *filter, const char *effectName, const char *paramName, int *intValue, int n);
    
    void changeHotFilterStringValue(int layerID, const char *filter, const char *effectName, const char *paramName, const char *stringValue);
    
    void visibleHotFilter(int layerID, const char *filter, int isVisible);
    
public:
    void render() {
        std::lock_guard<std::mutex> lock(mMutex);
        mContext->drawBefore();
        auto size = mContext->getSizeSRC();
        shared_ptr<STDSRenderTarget> dstFbo = nullptr;
        for (auto layer: mLayers) {
            if (layer->isVisible() == false) {
                continue;
            }
            // 绘制图层
            auto fbo = make_shared<STDSRenderTarget>(size.x, size.y);
            fbo->bindSelf();
            layer->draw();
            fbo->restore();
            
            if (dstFbo == nullptr) {
                dstFbo = fbo;
                continue;
            }
            // 绘制blend
            auto blendFbo = make_shared<STDSRenderTarget>(size.x, size.y);
            blendFbo->bindSelf();
            drawBlend(fbo->getTexture(), dstFbo->getTexture(), layer->getBlend());
            blendFbo->restore();
            dstFbo = blendFbo;
        }
        if (dstFbo != nullptr) {
            drawTexture(dstFbo->getTexture());
        }
        mContext->drawAfter();
    }
    
    void readPixel(int *width, int *height, unsigned char **data) {
        std::lock_guard<std::mutex> lock(mMutex);
        mContext->drawBefore();
        auto size = mContext->getSizeSRC();
        shared_ptr<STDSRenderTarget> dstFbo = nullptr;
        for (auto layer: mLayers) {
            if (layer->isVisible() == false) {
                continue;
            }
            // 绘制图层
            auto fbo = make_shared<STDSRenderTarget>(size.x, size.y);
            fbo->bindSelf();
            layer->draw();
            fbo->restore();
            
            if (dstFbo == nullptr) {
                dstFbo = fbo;
                continue;
            }
            // 绘制blend
            auto blendFbo = make_shared<STDSRenderTarget>(size.x, size.y);
            blendFbo->bindSelf();
            drawBlend(fbo->getTexture(), dstFbo->getTexture(), layer->getBlend());
            blendFbo->restore();
            dstFbo = blendFbo;
        }
        if (dstFbo != nullptr) {
            auto fbo = make_shared<STDSRenderTarget>(size.x, size.y);
            fbo->bindSelf();
            drawTexture(dstFbo->getTexture());
            *width = size.x;
            *height = size.y;
            void *pixelsDATA = malloc(int(size.x) * int(size.y) << 2);
            glReadPixels(0, 0, size.x, size.y, GL_RGBA, GL_UNSIGNED_BYTE, pixelsDATA);
            *data = (unsigned char *)pixelsDATA;
            fbo->restore();
        }
        mContext->drawAfter();
    }
    
    void drawTexture(shared_ptr<STDSTexture> tex) {
        mDefaultEffect->setTexture(tex);
        mDefaultEffect->draw();
        mDefaultEffect->setTexture(nullptr);
    }
    
    void setCurrentPrograss(float prograss) {
        std::lock_guard<std::mutex> lock(mMutex);
        mCurPrograss = prograss;
        for (auto layer: mLayers) {
            layer->setPrograss(prograss);
        }
    }
    
    // 测试函数
    void test() {
        std::lock_guard<std::mutex> lock(mMutex);
        std::thread::id threadID = std::this_thread::get_id();
        std::cout << ">>>>>>>>>Current Thread test: " << threadID << std::endl;
    }
    
public:
    void replaceImageAsset(int layerId, int assetId, const char *path);
    
    void replaceImageTex(int layerId, int assetId, const unsigned int textureId, float width, float height);
    
    void replaceImageData(int layerId, int assetId, const unsigned char *data, float width, float height);
    
    void replaceMaskAsset(int layerId, int assetId, const char *path);
    
    void replaceMaskTex(int layerId, int assetId, const unsigned int textureId, float width, float height);
    
    void replaceMaskData(int layerId, int assetId, const unsigned char *data, float width, float height);

private:
    void drawBlend(shared_ptr<STDSTexture> srcTex, shared_ptr<STDSTexture> dstTex, STDSBlendType blend) {
        mBlendEffect->setDstTex(dstTex);
        mBlendEffect->setSrcTex(srcTex);
        mBlendEffect->setBlendType(blend);
        mBlendEffect->initGL();
        mBlendEffect->draw();
        mBlendEffect->unInitGL();
    }
    
    void moveLayerToFront(int layerID, int targetLayerID);
    
    void moveLayerToBack(int layerID, int targetLayerID);
    
    void moveLayerToTop(int layerID);
    
    void moveLayerToBottom(int layerID);
private:
    float mCurPrograss{0.0};
    float mDuration{0.0};
    shared_ptr<STDSGLContext> mContext{nullptr};
    shared_ptr<STDSBlendEffect> mBlendEffect{nullptr};
    shared_ptr<STDSDefaultEffect> mDefaultEffect{nullptr};//默认效果
    vector<shared_ptr<STDBaseLayer>> mLayers;
    mutex mMutex;
};
#endif /* RenderManager_hpp */
